“小语言”才是编程的未来! 您所在的位置:网站首页 sql 高级编程 “小语言”才是编程的未来!

“小语言”才是编程的未来!

2023-03-24 11:41| 来源: 网络整理| 查看: 265

摘要:随着软件功能不断增加,代码数量也日益膨胀,我们要如何停止不断堆砌,甚至缩小软件体积?本文作者提出了一种可能性:“小语言”。

链接:https://chreke.com/little-languages.html

声明:本文为 CSDN 翻译,未经允许禁止转载。

作者| Christoffer Ekeroth      

译者 | 弯月   责编 | 郑丽媛

出品 | CSDN(ID:CSDNnews)

我认为,“小语言”——旨在解决非常具体问题的小语言——是编程的未来,尤其是在阅读了 Gabriella Gonzalez 的文章《编程历史的终结》(The end of history for programming),并观看了 Alan Kay 的演讲《编程与扩展》之后,我更加确定了这个看法。

什么是“小语言”?

“小语言”这个词源自 Jon Bentley 的一篇文章《Little Languages》(小语言),他给出的定义如下:

……小语言指的是专门针对某个特定问题领域的编程语言,不包含传统语言的许多功能。

举个例子,SQL 就是一种描述数据库操作的小语言,正则表达式是一种用于文本匹配的小语言,Dhall 是一种用于配置管理的小语言,等等。

这些语言还有一些其他名称,比如领域特定语言(Domain-specific languages,简称 DSL)、面向问题的语言等等。但是,我最喜欢“小语言”这种叫法,有一部分原因是“DSL”一词包含的含义太多了,包括从具有流式接口的库到成熟的查询语言(如 SQL)。此外,“小语言”这种叫法还强调了这类语言的一个本质:小。

为什么我们需要小语言?

从工程的发展史来看,如今的软件也属于某种工程,但从事这种工程的人并不懂得“拱门”为何物。现在大多数软件与埃及金字塔非常相像,由数百万块砖相互堆叠而成,没有结构完整性,只是靠蛮力和成千上万的奴隶建造的。

—— 艾伦·凯,摘自《与艾伦·凯的对话》

软件工程社区真正遇到的问题是,随着应用程序的复杂性增加,其源代码的规模也会随之增加。然而,我们知道大型代码库的能力在很大程度上仍然是固定的。根据 Sourcegraph 于 2020 年发起的一项调查 The Emergence of Big Code 表明,大多人都表示他们的代码库出现了以下一个或多个问题:

很难添加新员工;

缺乏对依赖关系的理解,导致代码出问题;

代码变更的管理难度越来越大。

更糟糕的是,应用程序正以惊人的速度增长,据 Sourcegraph 调查,大多人认为他们的代码库在过去十年中增长了 100~500 倍。举一个具体的例子,1992 年 Linux 内核刚问世时只有大约 1 万行代码,但在 20 年后的今天已经达到了 3000 万行。

这些代码从何而来?我认为“更多功能”不足以解释这些代码量的增加,相反,我认为这与我们构建软件的方式有关。在程序中添加新功能的常见方法是:在现有功能之上不断堆叠——这不恰恰就是金字塔的搭建方式吗?不同的是,每一层所需要的砖会越来越多。

逆势而上

问题是,我们真的需要数百万行代码来构建现代操作系统吗?2006 年,Alan Kay 与 STEPS 项目的合作者开始挑战这个假设:

科学的进步需要结合实证研究与理论模型,所以作为科学家,我们的首要问题是,如果我们以个人计算现象为基础建立一个模型,是否可以将其提炼为极度简化的东西,就像适用于所有电磁波谱的麦克斯韦方程组,或者是可以浓缩至衬衫口袋大小的美国宪法?还是说这个模型非常混乱(或者极端复杂),就像美国的法律体系(或当前的软件实践)一样“堆积起来有 3 立方英里”那么高的判例法?答案几乎是肯定的:介于两者之间。果真如此的话,能证明这个模型更接近于简化,而不是极端复杂,那一定非常有趣。

所以,我们的问题是:个人计算体验(将操作系统、应用以及其他支持软件的经验都算在内)本质上指的是多少行代码?20 亿行、2 亿行、2 千万行、2 百万行、20 万行、2 万行还是 2 千行?

—— 《STEPS 2007 年进度报告》,第 4~5 页

这里,Kay 提到的麦克斯韦方程组是一组描述电磁学、光学和电路基础的方程式。这些方程式的使用范围非常广,但方程式本身很紧凑,甚至可以印到 T 恤衫上:

这些方程式如此简洁的原因之一是,使用了 Del 符号(∇)来描述向量微积分运算。需要注意的一点是,Del 并不是真正的运算符,它更像是一种简写形式,可以方便我们使用向量微积分中的某些方程。

那么,我们可以创建编程界的 Del 符号吗?就像 Del 可以让向量演算更易于管理一样,我们是否可以找到某种符号,以相同的方式帮助我们理解程序?这个问题正是 STEPS 项目背后的核心思路之一:

此外,我们认为创建面向问题的语言可以降低解决问题的难度,可以使解决方案更易于理解且更小,并且也符合我们“主动数学”方法的精神。这些“面向问题的语言”将被创建并用于大大小小的问题,以及不同层次的抽象和细节。

—— 《STEPS 2007 年进度报告》,第 6 页

这里的基本思路是,在寻找应用程序中的模式时,你可以用一种小语言将它们编码,这种语言将允许你以比其他抽象方法更紧凑的方式来表达这些模式。这样不仅可以逆转应用程序不断增长的趋势,而且还可以让代码库在开发的过程中缩小!

我发现,Nile(https://github.com/damelang/nile)是 STEPS 计划的一大成果,这是一种用于描述图形渲染和合成的小语言,目标是使用 Nile 实现与 Cairo 相同水平的功能。Cairo 是各种免费软件项目都在使用的一种开源渲染器,总代码量约为 44,000 行——而 Nile 只有大约 300 行。

为什么不是高级语言?

尽管如此,事实证明 Ada 并不是干掉软件生产力怪物的灵丹妙药。毕竟,它也只是一种高级语言,这类语言带来的最大收益来自第一次转变,从机器意外的复杂性上升到更抽象的逐步解决方案。在剔除这些意外后,剩下的意外就会变少,而剔除它们的回报自然也会减少。

—— Frederick P. Brooks,《No Silver Bullet》

说到这里,你可能想问:“为什么我们不能发明一种更高级的通用语言呢?”我认为,通用语言的表达能力带给我们的收益已在递减。那么,更高级的语言将是什么样子呢?以 Python 为例,这门语言如此高级,看起来已经很像伪代码了。

通用语言的问题在于,你仍然需要将问题转化为算法,然后再用语言表达算法。如今的高级语言非常擅长描述算法,但除非你的目标是实现算法,否则它也会意外的复杂。

在写这篇文章的时候,我想起了一个关于 Donald Knuth 的故事:有人让 Knuth 在 Jon Bentley 的 Programming Pearls 专栏中展示他的编程风格,而 Doug McIlroy 应邀对 Knuth 的程序发表评论。

Knuth 的任务是计算某一段文本中的词频,其解决方案是用 WEB 语言精心编写的,这门语言是 Pascal 的变体,也是他自己编写的。Knuth 添加了一个专门用于跟踪字数的数据结构,所有代码不到 10 页。虽然 McIlroy 很快就称赞了 Knuth 的解决方案,但他对程序本身并不是很满意。作为评论的一部分,他用 shell 脚本、Unix 命令和小语言编写了自己的解决方案:

对于不熟悉 Unix 的人来说,这段代码不太容易理解——McIlroy 本人也承认这一点,他甚至添加了一个带注释的版本。但很显然,相比十页的程序,这段代码更容易理解。

Unix 命令是为操作文本而设计的,这就是为什么 McIlroy 可以编写出一个如此紧凑的字数统计程序。或许,我们可以将 shell 脚本视为文本操作的“Del 符号”?

少即是多

上述 Unix 命令示例说明了小语言的另一个特征:语言本身不是特别强大,但运行时非常强大。Gonzalez 在文章《编程历史的终结》中提到了如下趋势:

在研究上述趋势时,我们发现了一个共同的模式:将用户关心的某个问题转变成运行时的问题,可以……让使程序更像纯数学表达式,并且……运行时的复杂性明显增加。

正则表达式和 SQL 只能用于表达文本搜索和数据库操作。与之相对的是,C 等没有运行时的语言,你可以表达任何在冯-诺伊曼架构上可能出现的东西。而 Python 和 Haskell 等高级语言介于两者之间:你无需在意内存管理,但仍然可以使用图灵完备语言的全部功能,这意味着你可以表达任何计算。

小语言和 C 语言处于两个极端。对于小语言来说,不仅计算机的体系结构被抽象掉了,其中一些语言可以表达的程序种类也有限制——它们在设计上是不具备图灵完备性的。虽然听上去这些语言非常受限,但实际上它们为优化和静态分析开辟了全新的可能性。而且,就像抽象出内存管理可以消除一大类错误一样,尽可能地抽象出算法也有助于消灭更多的错误。

静态分析

功能不是十分强大的语言更容易推理,而且可以提供比通用语言更强的保证。例如,Dhall 是一种用于生成配置文件的全功能编程语言,如果你不想冒险让部署脚本崩溃或将它们置于无限循环中,则可以考虑 Dhall,因为它可以保证:

1.不崩溃;

2.在有限的时间内结束。

第一点的实现方式是不抛出异常,任何可能失败的操作(例如获取空列表中的第一个元素)都会返回一个可选的结果,其中可能包含值,也可能不包含。第二,为了保证结束,Dhall 不允许程序使用递归定义。在其他函数式编程语言中,递归是表达循环的主要方式,但在 Dhall 中,你必须依赖内置的 fold 函数。缺少通用的循环结构意味着 Dhall 不是图灵完备的语言,但由于它不是一种通用的编程语言,所以也没有这个必要。

如果语言很小,理解起来就更容易。例如,你很难确认 Python 程序是否有副作用,但对于 SQL 来说却很简单,你只需检查查询是否以 SELECT 开头。

对于 Nile,STEPS 团队看到了对图形调试器的需求。Bret Victor 想出了一个工具,可以告诉你在屏幕上绘制特定像素的代码。你可以通过 YouTube 观看 Alan Kay 的演示,也可以自己动手尝试一下。这样的工具是完全可行的,因为 Nile 是一种易于推理的小型语言——想象一下,如果用 C++ 编写同样的一款工具会是什么样子?

对速度的要求

强大的编程语言不仅会增加出现 bug 的可能性,还会对性能产生不利影响。例如,一个程序没有用算法来表达,运行时可以自由选择;我们可以用更快的表达式来替换,当然前提是我们能证明它们能产生相同的结果。

例如,SQL 查询并没有规定应该如何执行查询,数据库引擎可以自由使用它认为最合适的任何查询计划,例如应该使用一个索引、多个索引的组合,还是直接扫描整个数据库表。现代数据库引擎还会收集有关列的值分布的统计信息,这样它们就可以即时选择最优的查询计划。如果查询是通过算法的方式描述的,那就不可能了。

Nile 语言如此紧凑的“秘密武器”之一是 Jitblt,这是一种用于图形渲染的即时编译器。从 STEPS 和 Cairo 团队之间的讨论可以清楚地看出,Cairo 的许多代码都是手动优化像素的合成操作,理论上这部分工作可以交给编译器。因此 Cairo 团队的 Dan Amelang 实现了这样的一个编译器,它就是 Jitblt。这意味着,图形流水线的优化工作可以与渲染内容的纯数学描述分离,这也是 Nile 的运行速度与手动优化过的 Cairo 一样快的原因。

小语言,大潜力

那么,STEPS 项目最后怎么样了?他们最终得到了“堆积起来有 3 立方英里的判例法”,还是设法创建了一个“可以印到 T 恤衫上的操作系统”?他们的最终结果是 KSWorld,这是一个完整的操作系统,包括文档编辑器和电子表格编辑器,大约有 17000 行代码。虽然无法印到 T 恤衫上,但我仍然认为这个项目是成功的。

KSWorld 的创建表明小语言有很大的潜力。然而,我们还有许多问题没有解决,例如这些小语言之间应该如何互通?它们应该编译成一个通用的中间表示吗?或者使用不同的运行时,然后通过通用协议(例如 UNIX 管道或 TCP/IP)相互通信?或者,也许每种语言足够小,可以用各种不同的宿主语言重新实现(如正则表达式)?亦或者,我们可以结合使用这些方式?

无论怎样,我认为我们需要一种不同的方式来构建软件。小语言能否成为这条发展道路上的一部分,也许我们还没有答案,但重要的是我们必须停止不断堆砌砖头,同时还需要想出一种更好的办法。

感恩福利日



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有